package com.ts.main.mini.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ts.main.mini.config.JsapiConfig;
import com.ts.main.mini.context.UserContext;
import com.ts.main.mini.dto.OrderDto;
import com.ts.main.mini.dto.OrderPageSearchDto;
import com.ts.main.mini.dto.OrderSearchDto;
import com.ts.main.mini.entity.OrderEntity;
import com.ts.main.mini.entity.ProductVariantEntity;
import com.ts.main.mini.enums.OrderStatusEnum;
import com.ts.main.mini.exception.CommonException;
import com.ts.main.mini.exception.RPage;
import com.ts.main.mini.mapper.OrderMapper;
import com.ts.main.mini.properties.WxPayProperties;
import com.ts.main.mini.vo.OrderDetailsVo;
import com.ts.main.mini.vo.OrderVo;
import com.ts.main.mini.vo.TransactionVo;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.CloseOrderRequest;
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author lk
 * @description 针对表【t_order(用户订单表)】的数据库操作Service实现
 * @createDate 2025-05-16 15:11:43
 */
@Slf4j
@AllArgsConstructor
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderEntity> {

    private final WxPayProperties wxPayProperties;
    private final JsapiConfig jsapiConfig;
    private final ReentrantLock lock = new ReentrantLock(true);

    private final ProductVariantServiceImpl productVariantService;
    private final ShoppingCartServiceImpl shoppingCartService;

    public RPage<List<OrderVo>> getOrderPage(OrderPageSearchDto dto) {
        Integer userId = UserContext.getUser().getUserId();
        dto.setUserId(userId);
        Page<Object> page = PageHelper.startPage(dto.getPage(), dto.getLimit());
        List<OrderVo> list = baseMapper.getOrderPage(dto);
        return RPage.ok(list, dto.getPage(), dto.getLimit(), page.getTotal());
    }

    public List<OrderVo> getOrderList(OrderSearchDto dto) {
        Integer userId = UserContext.getUser().getUserId();
        dto.setUserId(userId);
        return baseMapper.getOrderList(dto);
    }

    public OrderDetailsVo getOrderDetails(Integer orderId) {
        return baseMapper.getOrderDetails(orderId);
    }

    public OrderVo getOrderByOrderNumber(String orderNumber) {
        return baseMapper.getOrderByOrderNumber(orderNumber);
    }


    public String getOrderStatus(Integer orderId) {
        return getById(orderId).getOrderStatus();
    }


    @Transactional
    public String saveOrder(OrderDto dto) {
        Integer userId = UserContext.getUser().getUserId();
        dto.setUserId(userId);
        //商品信息
        ProductVariantEntity variantEntity = productVariantService.getById(dto.getVariantId());
        //校验商品库存
        productVariantService.reduceStockQuantity(dto.getVariantId(), dto.getProductCount());
        //计算商品总价格
        String actualPrice = variantEntity.getPrice();
        BigDecimal totalAmount = new BigDecimal(dto.getProductCount())
                .multiply(new BigDecimal(actualPrice))
                .setScale(2, RoundingMode.HALF_UP);
        //完善订单信息
        //订单唯一编号
        String orderNumber = IdUtil.objectId();
        OrderEntity orderEntity = new OrderEntity();
        BeanUtil.copyProperties(dto, orderEntity);
        orderEntity.setOrderNumber(orderNumber);
        orderEntity.setProductPrice(actualPrice);
        orderEntity.setTotalAmount(String.valueOf(totalAmount));
        orderEntity.setMustPayAmount(String.valueOf(totalAmount));
        orderEntity.setWaitPayAmount(String.valueOf(totalAmount));
        orderEntity.setOrderStatus(OrderStatusEnum.OBLIGATION.getTypeValue());
        orderEntity.setOrderSort(OrderStatusEnum.OBLIGATION.getTypeOrder());
        orderEntity.setEffectiveTime(LocalDateTime.now().plusDays(3));
        orderEntity.setUserPayTime(null);
        orderEntity.setIsDeleted(false);
        //
        save(orderEntity);
        //删除购物车数据
        if (!ObjectUtil.isEmpty(dto.getCartId())) {
            shoppingCartService.deleteCart(List.of(dto.getCartId()));
        }
        return orderNumber;
    }


    @Transactional
    public Boolean cancelOrder(Integer orderId) {
        // 获取订单信息
        OrderEntity orderEntity = getById(orderId);
        Integer orderSort = orderEntity.getOrderSort();
        String orderNumber = orderEntity.getOrderNumber();
        String totalAmount = orderEntity.getTotalAmount();
        // 校验订单状态，只有待付款和未发货可以取消订单
        if (orderSort > 2) {
            throw new CommonException("订单未完结，不能取消");
        }
        // 关闭和退款订单的操作
        switch (orderSort) {
            case 1:
                handlePaymentPendingOrder(orderNumber);
                break;
            case 2:
                handlePaidOrder(orderNumber, totalAmount);
                break;
            default:
                log.warn("未知订单状态: {}", orderSort);
                throw new CommonException("无法处理该订单");
        }
        // 回滚商品库存
        productVariantService.increaseStockQuantity(orderEntity.getVariantId(), orderEntity.getProductCount());
        // 更新订单状态为已取消
        return updateOrderStatusToCancelled(orderId);
    }

    private void handlePaymentPendingOrder(String orderNumber) {
        // 查询订单状态
        TransactionVo transactionVo = queryOrderByOutTradeNo(orderNumber);
        if (!ObjectUtil.isEmpty(transactionVo)) {
            // 关闭待付款订单
            log.info("关闭待付款订单: {}", orderNumber);
            closeOrder(orderNumber);
        }
    }

    /**
     * 取消支付（关闭支付订单）
     *
     * @param orderNumber
     */
    public void closeOrder(String orderNumber) {
        if(lock.tryLock()){
            try {
                //初始化服务
                JsapiServiceExtension service = new JsapiServiceExtension
                        .Builder()
                        .config(jsapiConfig.initConfig())
                        .build();

                CloseOrderRequest request = new CloseOrderRequest();
                request.setMchid(wxPayProperties.getMerchantId());
                request.setOutTradeNo(orderNumber);
                service.closeOrder(request);
            }finally {
                lock.unlock();
            }
        }
    }

    /**
     * 商户订单号查询订单
     *
     * @param outTradeNo
     * @return
     */
    public TransactionVo queryOrderByOutTradeNo(String outTradeNo) {
        //初始化服务
        JsapiServiceExtension service = new JsapiServiceExtension
                .Builder()
                .config(jsapiConfig.initConfig())
                .build();
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setOutTradeNo(outTradeNo);
        request.setMchid(wxPayProperties.getMerchantId());
        Transaction transaction = service.queryOrderByOutTradeNo(request);
        return BeanUtil.copyProperties(transaction, TransactionVo.class);
    }


    private void handlePaidOrder(String orderNumber, String totalAmount) {
        // 退款处理（订单支付完成后自动关闭）
        log.info("退款处理: {},金额：{}", orderNumber, totalAmount);
        refundOrder(orderNumber, totalAmount);
    }

    /**
     * 微信申请退款
     *
     * @param orderNumber 商户订单号
     * @param totalAmount 退款金额，单位分
     * @return
     */
    public Boolean refundOrder(String orderNumber, String totalAmount) {
        if(lock.tryLock()){
            try {
                // 构建退款service
                RefundService service = new RefundService.Builder()
                        .config(jsapiConfig.initConfig())  // 配置微信支付
                        .build();
                // 创建退款请求
                CreateRequest request = new CreateRequest();
                request.setOutTradeNo(orderNumber);               // 设置商户订单号
                request.setOutRefundNo("REFUND_" + orderNumber);  // 设置退款订单号

                // 设置退款金额
                BigDecimal totalAmountNew = new BigDecimal(totalAmount)
                        .multiply(new BigDecimal(100))
                        .setScale(0, RoundingMode.HALF_UP);
                log.info("totalAmountNew{}", totalAmountNew);
                AmountReq amount = new AmountReq();
                long totalAmountLong = totalAmountNew.longValue(); // 获取总金额（分）
                amount.setTotal(totalAmountLong);  // 总金额
                amount.setRefund(totalAmountLong); // 退款金额
                amount.setCurrency("CNY");         // 货币单位，人民币

                request.setAmount(amount);
                request.setNotifyUrl(wxPayProperties.getRefundNotifyUrl());  // 设置退款通知URL

                // 执行退款请求
                Refund refund = service.create(request);
                log.info("退款返回信息：{}", refund);

                // 根据退款状态处理不同情况
                switch (refund.getStatus()) {
                    case Status.SUCCESS:
                        log.info("退款成功，交易号：{}", refund.getTransactionId());
                        return true;
                    case Status.ABNORMAL:
                        log.error("退款失败，账户异常，订单号：{}", orderNumber);
                        throw new CommonException("退款失败，账户异常！");
                    case Status.PROCESSING:
                        log.warn("退款处理中，订单号：{}", orderNumber);
                        throw new CommonException("退款正在处理中！");
                    case Status.CLOSED:
                        log.error("退款失败，余额不足或订单已关闭，订单号：{}", orderNumber);
                        throw new CommonException("退款失败，用户余额不足或订单超过退款期限！");
                    default:
                        log.error("退款失败，未知错误，订单号：{}", orderNumber);
                        throw new CommonException("退款失败，未知错误！");
                }
            } catch (ServiceException e) {
                // 处理微信支付服务异常
                log.error("微信退款失败，错误信息：{}", e.getErrorMessage());
                throw new CommonException("退款失败！" + e.getErrorMessage());
            } catch (NumberFormatException e) {
                // 捕获格式化错误，处理金额转换问题
                log.error("退款金额格式错误，错误信息：{}", e.getMessage());
                throw new CommonException("退款金额格式错误！");
            } catch (Exception e) {
                // 处理其他非预期异常
                log.error("服务返回成功，返回体类型不合法，或者解析返回体失败，错误信息：{}", e.getMessage());
                throw new CommonException("退款失败！" + e.getMessage());
            }finally {
                lock.unlock();
            }
        }else {
            log.info("当前业务繁忙，请稍后重试");
            throw new CommonException("当前业务繁忙，请稍后重试");
        }
    }

    private Boolean updateOrderStatusToCancelled(Integer orderId) {
        LambdaUpdateWrapper<OrderEntity> updateWrapper = new LambdaUpdateWrapper<OrderEntity>()
                .set(OrderEntity::getOrderStatus, OrderStatusEnum.CANCELLED.getTypeValue())
                .set(OrderEntity::getOrderSort, OrderStatusEnum.CANCELLED.getTypeOrder())
                .eq(OrderEntity::getOrderId, orderId);
        return update(updateWrapper);
    }

    public Boolean updateOrderStausByNumber(String orderNumber, String openid, String amount, String status, Integer orderSort) {
        LambdaUpdateWrapper<OrderEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(OrderEntity::getUserPayTime, LocalDateTime.now())
                .set(OrderEntity::getUserOpenid, openid)
                .set(OrderEntity::getActualPayAmount, amount)
                .set(OrderEntity::getOrderStatus, status)
                .set(OrderEntity::getOrderSort, orderSort)
                .eq(OrderEntity::getOrderNumber, orderNumber);
        return update(updateWrapper);
    }

    public Boolean updateOrderStausByNumber(String orderNumber, String status, Integer orderSort) {
        LambdaUpdateWrapper<OrderEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(OrderEntity::getUserPayTime, LocalDateTime.now())
                .set(OrderEntity::getOrderStatus, status)
                .set(OrderEntity::getOrderSort, orderSort)
                .eq(OrderEntity::getOrderNumber, orderNumber);
        return update(updateWrapper);
    }


    public Boolean confirmOrder(Integer orderId) {
        OrderEntity order = getById(orderId);
        if (!order.getOrderStatus().equals(OrderStatusEnum.DELIVER.getTypeValue())) {
            throw new CommonException("订单未发货，确认收货失败");
        }
        LambdaUpdateWrapper<OrderEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(OrderEntity::getOrderStatus, OrderStatusEnum.COMPLETED.getTypeValue())
                .set(OrderEntity::getOrderSort, OrderStatusEnum.COMPLETED.getTypeOrder())
                .eq(OrderEntity::getOrderId, orderId);
        return update(updateWrapper);
    }

}




